#pragma once
#include "../ComPtrEx.h"
#include "../DllModule.h"
#include "../Resources/Resources.h"
#include "../SevenZip/SevenZipArchive.h"
#include "../SevenZip/SevenZipArchiveItem.h"
#include "../SevenZip/Factory.h"

#define ZIPFOLDER_ITEM_MAGIC DWORD('piZ7') // 7Zip

struct ZIPFOLDER_ITEM
{
	UINT32 ItemIndex;
};

typedef ZIPFOLDER_ITEM * PZIPFOLDER_ITEM;
typedef CONST ZIPFOLDER_ITEM * PCZIPFOLDER_ITEM;

struct ZIPFOLDER_COLUMN
{
	PROPERTYKEY Property;
	SHCOLSTATEF ColumnState;
};

struct CPropertyStoreFactory;

struct CSevenZipFolder : CComObjectRootEx<CComSingleThreadModel>,
                         CComCoClass<CSevenZipFolder, &CLSID_SevenZipFolder>,
                         CItemIDFactory<ZIPFOLDER_ITEM, ZIPFOLDER_ITEM_MAGIC>,
                         IPersistFolder2,
                         IShellFolder2
{
	DECLARE_REGISTRY_RESOURCEID(IDR_SevenZipFolder)
	DECLARE_NOT_AGGREGATABLE(CSevenZipFolder)

	BEGIN_COM_MAP(CSevenZipFolder)
		COM_INTERFACE_ENTRY(IPersist)

		COM_INTERFACE_ENTRY(IPersistFolder)
		COM_INTERFACE_ENTRY(IPersistFolder2)

		COM_INTERFACE_ENTRY(IShellFolder)
		COM_INTERFACE_ENTRY(IShellFolder2)
	END_COM_MAP()

	BEGIN_CATEGORY_MAP(CSevenZipFolder)
		IMPLEMENTED_CATEGORY(CATID_BrowsableShellExt)
	END_CATEGORY_MAP()

    DECLARE_PROTECT_FINAL_CONSTRUCT()

    HRESULT FinalConstruct();
    VOID    FinalRelease();

	// IPersist

	IFACEMETHODIMP GetClassID(__out CLSID *);

    // IPersistFolder
    
	IFACEMETHODIMP Initialize(__in PCIDLIST_ABSOLUTE);

    // IPersistFolder2

	IFACEMETHODIMP GetCurFolder(__out PIDLIST_ABSOLUTE *);

	// IShellFolder

	IFACEMETHODIMP ParseDisplayName( __in_opt HWND, 
	                                 __in_opt IBindCtx *, 
								     __in     PWSTR, 
								    __out_opt ULONG *, 
								    __out     PIDLIST_RELATIVE *, 
								  __inout_opt ULONG *);

	IFACEMETHODIMP EnumObjects(   __in_opt HWND, 
		                                   SHCONTF, 
							   __deref_out IEnumIDList **);

	IFACEMETHODIMP BindToObject(     __in     PCUIDLIST_RELATIVE, 
		                             __in_opt IBindCtx *, 
								     __in     REFIID, 
								  __deref_out VOID **);

	IFACEMETHODIMP BindToStorage(    __in     PCUIDLIST_RELATIVE, 
		                             __in_opt IBindCtx *, 
								     __in     REFIID, 
								  __deref_out VOID **);

	IFACEMETHODIMP CompareIDs(                LPARAM, 
		                                 __in PCUIDLIST_RELATIVE, 
									     __in PCUIDLIST_RELATIVE);

	IFACEMETHODIMP CreateViewObject(     __in HWND, 
		                                 __in REFIID, 
								  __deref_out VOID **);

	IFACEMETHODIMP GetAttributesOf(           UINT Count, 
		               __in_ecount_opt(Count) PCUITEMID_CHILD_ARRAY, 
					                          SFGAOF *);

	IFACEMETHODIMP GetUIObjectOf(        __in HWND, 
		                                      UINT, 
										 __in PCUITEMID_CHILD_ARRAY, 
										 __in REFIID, 
								   __reserved UINT *, 
								  __deref_out VOID **);

	IFACEMETHODIMP GetDisplayNameOf( __in PCUITEMID_CHILD, 
		                                  SHGDNF, 
								    __out STRRET *);

	IFACEMETHODIMP SetNameOf(__in_opt    HWND, 
		                     __in        PCUITEMID_CHILD, 
							 __in        PCWSTR, 
							  		     DWORD, 
							 __deref_out PITEMID_CHILD *);

	// IShellFolder2

	IFACEMETHODIMP GetDefaultSearchGUID(__out LPGUID);
    IFACEMETHODIMP EnumSearches(__deref_out IEnumExtraSearch **);
    
	IFACEMETHODIMP GetDefaultColumn(      DWORD, 
		                            __out PULONG, 
									__out PULONG);
    
	IFACEMETHODIMP GetDefaultColumnState(      UINT, 
		                                 __out SHCOLSTATEF *);

	IFACEMETHODIMP GetDetailsEx(__in PCUITEMID_CHILD, 
		                        __in CONST PROPERTYKEY *, 
							   __out LPVARIANT);
    
	IFACEMETHODIMP GetDetailsOf(__in_opt PCUITEMID_CHILD, 
		                                 UINT,
	                               __out SHELLDETAILS *);

    IFACEMETHODIMP MapColumnToSCID(UINT, __out PROPERTYKEY *);

	STDMETHODIMP _CreateItemID(UINT32, __deref_out PITEMID_CHILD *);
	STDMETHODIMP _CreateItemID(UINT32, __deref_out PIDLIST_RELATIVE *);
	
private:
	
	STDMETHODIMP _GetDetailsEx(__in PCUITEMID_CHILD,
		                       __in REFPROPERTYKEY,
						      __out CComPropVariant &);

	STDMETHODIMP _GetUIObjectOfItem(__in SevenZip::CSevenZipArchiveItem *,
		                            __in REFIID, 
									__deref_out VOID * *);

	STDMETHODIMP _GetItemByItemID(__in PCUIDLIST_RELATIVE, 
		                   __deref_out SevenZip::CSevenZipArchiveItem * *);
 
	STDMETHODIMP _GetItemByItemID(__in SevenZip::CSevenZipArchiveItem *,
		                          __in PCUIDLIST_RELATIVE, 
				           __deref_out SevenZip::CSevenZipArchiveItem * *);

	STDMETHODIMP _GetItemByItemIDList(__in PCUIDLIST_RELATIVE, 
						       __deref_out SevenZip::CSevenZipArchiveItem * *);

	STDMETHODIMP _GetItemByItemIDList(__in SevenZip::CSevenZipArchiveItem *,
		                              __in PCUIDLIST_RELATIVE, 
							   __deref_out SevenZip::CSevenZipArchiveItem * *);

	STDMETHODIMP _CreatePropertyStoreFactory(__in PCUIDLIST_RELATIVE, CComPtr<CPropertyStoreFactory> &);

	STDMETHODIMP _CreatePropertyStoreFactory(UINT, CComPtr<CPropertyStoreFactory> &);

	STDMETHODIMP _CreatePropertyStoreFactory(__in SevenZip::CSevenZipArchiveItem *, CComPtr<CPropertyStoreFactory> &);

	static STDMETHODIMP _GetPathFromItemIDList(__in PCIDLIST_ABSOLUTE,
	                                                CStringW &,
									                CComMemPtr<ITEMIDLIST_RELATIVE> &);

	static STDMETHODIMP _CreateFolderIExtractIcon(__in REFIID, __deref_out VOID * *);
	static STDMETHODIMP _CreateFileIExtractIcon(__in CStringW &, __in REFIID, __deref_out VOID * *);

private:

	CStringW _ArchivePath;
	CComMemPtr<ITEMIDLIST_ABSOLUTE> _Location;

	SevenZip::CSevenZipFactoryPtr _Factory;
	SevenZip::CSevenZipArchivePtr _Archive;

	SevenZip::CSevenZipArchiveItem * _Folder;

	static CONST ZIPFOLDER_COLUMN Columns[];
};

typedef CComPtrEx<CSevenZipFolder> CSevenZipFolderPtr;